#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import json
import locale
import os
import shlex
import shutil
import stat
import subprocess
import sys
import time
from multiprocessing import Manager, cpu_count

import psutil

from common.cleaner import clear
from common.common import execute_cmd, exter_attack
from common.common_models import SubJobModel, LogDetail, SubJobDetails
from common.const import SysData, SubJobStatusEnum, BackupJobResult, RepositoryDataTypeEnum
from exchange import log
from exchange.backup.exchange_backup_base import ExchangeBackupBase
from exchange.backup.exchange_mailbox_exec_backup import ExchangeMailBoxService
from exchange.commons.common import read_temp_file, check_del_dir_or_file, output_action_result, \
    output_result_file, get_key_value, mailbox_anonymization, report_job_details_by_rpc, check_exchange_mailbox_exist, \
    get_windows_server_version
from exchange.commons.const import ExchangeCode, ParamConstant, BodyErr, JobBackupType, TaskStage, SubJobPriorityEnum, \
    ExchangeMailBosConstants, ExchangeWindowsPath, ExchangeReportDBLabel
from exchange.commons.exchange_exception import ExchangeInternalException
from oceanbase.common.const import LogLevel

DAG_NODE = "DAG"
SINGLE_NODE = "Single"


def get_command_result(command):
    tmp_code = locale.getdefaultlocale()[1]
    if "|" in command:
        raise Exception("Special characters exist.")

    process = subprocess.Popen(shlex.split(command), stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE, encoding=tmp_code, errors="ignore")
    process.wait()
    code, out, err = str(process.returncode), process.stdout.read(), process.stderr.read()
    return code, out, err


def stop_child_process(process):
    for child in process.children(recursive=True):
        child_pid = child.pid
        child_cmd = child.cmdline()
        try:
            child.terminate()
            log.info(f"mailbox kill child: {child_pid}")
        except Exception as e:
            log.info(f"mailbox kill child: {child_pid} failed, error: {e}")


class ExchangeMailboxBackupComm(ExchangeBackupBase):
    m_func_type = ""
    m_check_output = {'code': ExchangeCode.FAILED.value, 'bodyErr': 0, 'message': ''}

    def __init__(self, pid, job_id, sub_job_id):
        log.info("init start!")
        self._exchange_object = None
        self._database_type = ""
        self.pid = pid
        self._job_id = job_id
        self._sub_job_id = sub_job_id
        self.m_username = ""
        self.m_password = ""
        self.guid = ""
        self.mailbox_address = ""
        self.anonymization_mailbox = ""
        self.data_hub = ""
        self.meta_hub = ""
        self.m_progress = 50
        self.m_progress_status = SubJobStatusEnum.RUNNING.value
        self.job_type = ""
        self.backup_start_time = 0
        self.manager = Manager()
        self.process_shared_dict = self.manager.dict()
        self.process_num = min(cpu_count(), 8)
        self.windows_version = ""
        self.repo_path = ""

        file_path = os.path.join(ParamConstant.PARAM_FILE_PATH, f"param{self.pid}")
        json_param = read_temp_file(file_path)
        check_del_dir_or_file(file_path)
        self._json_param = json_param
        self.backup_continue = self._json_param.get("job").get("extendInfo").get("backup_continue", True)
        self.compatibility_mode = \
            self._json_param.get("job").get("protectEnv").get("extendInfo").get("compatibility_mode", "false")

        super().__init__(self.pid, self._job_id, self._sub_job_id, self._json_param)

    @exter_attack
    def allow_backup_in_local_node(self):
        """
        备份鉴权
        :return: True 运行成功, False 运行失败
        """
        log.info("allow_backup_in_local_node start!")
        # 获取要备份的邮箱
        self.mailbox_address = \
            self._json_param.get("job").get("protectObject").get("extendInfo").get("PrimarySmtpAddress")
        self.anonymization_mailbox = mailbox_anonymization(self.mailbox_address)

        ret = check_exchange_mailbox_exist(self.m_username, self.m_password, self.mailbox_address)
        if not ret:
            log.error(f"mailbox: {self.anonymization_mailbox} check exists FAILED!")
            output_action_result(self.pid, ExchangeCode.FAILED.value, BodyErr.ERR_PLUGIN_CANNOT_BACKUP.value, "")
            return False
        log.info(f"mailbox: {self.anonymization_mailbox} allow_backup_in_local_node SUCCESS!")
        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        return True

    @exter_attack
    def check_backup_job_type(self):
        """
        判断能否进行增量备份
        :return: True 可以执行增量, False:增量需要转全量
        """
        log.info("mailbox backup check_backup_job_type!")
        ret = self.check_can_backup_inc()
        if not ret:
            log.error("backup_prerequisite FAILED! check_can_backup_inc!")
            output_action_result(self.pid, ExchangeCode.FAILED.value, BodyErr.ERR_INC_TO_FULL.value, "")
            return False

        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        log.info("mailbox check_backup_job_type SUCCESSES")
        return True

    # 前置任务
    @exter_attack
    def backup_prerequisite(self):
        """
        备份前置任务
        :return: True 执行成功，False 执行失败
        """
        log.info("mailbox backup_prerequisite start!")
        self.m_progress = 50
        self.m_progress_status = SubJobStatusEnum.RUNNING.value
        # 获取要备份的邮箱 Guid
        self.guid = self._json_param.get("job").get("protectObject").get("id")

        self.get_data_hub_and_meta_hub_path(self._json_param.get("job").get("jobId"))
        ret = self.init_cache_and_data_directory(self.data_hub, self.meta_hub)
        if not ret:
            log.error("backup_prerequisite FAILED! init_cache_and_data_directory")
            output_action_result(self.pid, ExchangeCode.FAILED.value, BodyErr.ERR_PLUGIN_CANNOT_BACKUP.value, "")
            return False

        if not self.check_mailbox_backup_permissions():
            ret = self.create_mailbox_backup_permissions()
        if not ret:
            # 增加用户组权限失败
            log.error("backup_prerequisite FAILED! create_mailbox_backup_permissions")
            output_action_result(self.pid, ExchangeCode.FAILED.value, BodyErr.ERR_PLUGIN_CANNOT_BACKUP.value, "")
            return False
        if self.set_job_type():
            if self.job_type == ExchangeMailBosConstants.INC_BACKUP:
                latest_copy_id = self._json_param.get('job').get('extendInfo').get('latest_copy_id')
                self.repo_path = self.get_unc_path()
                last_full_backup_meta_file = os.path.join(self.repo_path, latest_copy_id,
                                                          ExchangeMailBosConstants.META_DIR,
                                                          ExchangeMailBosConstants.FULL_BACKUP)
                last_inc_backup_meta_file = os.path.join(self.repo_path, latest_copy_id,
                                                         ExchangeMailBosConstants.META_DIR,
                                                         ExchangeMailBosConstants.INC_BACKUP)
                if not os.path.exists(last_full_backup_meta_file) and not os.path.exists(last_inc_backup_meta_file):
                    log.error("backup_prerequisite FAILED! inc backup meta data not exist!")
                    log_detail = LogDetail(logInfo=ExchangeReportDBLabel.COPY_VERIFICATION_FAILED,
                                           logLevel=LogLevel.ERROR.value,
                                           logDetail=BodyErr.EXCHANGE_CHECK_DEPENDENCE_COPY_FAILED.value)
                    self.write_progress_to_file(SubJobStatusEnum.FAILED.value, 100, log_detail, "common")
                    return False
        else:
            log.error("backup_prerequisite FAILED! get backup job type failed")
            output_action_result(self.pid, ExchangeCode.FAILED.value, BodyErr.ERR_PLUGIN_CANNOT_BACKUP.value, "")
            return False

        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        log.info("FINISH output_action_result!!!")
        self.write_progress_to_file(SubJobStatusEnum.COMPLETED.value, 100, "", "common")
        log.info("backup_prerequisite SUCCESS!")
        return True

    def create_mailbox_backup_permissions(self):
        username = self.m_username.replace("\\", "\\\\")
        account_name = self.m_username.split("\\")[-1]
        cmds = f"{ParamConstant.PS_LOC} {ParamConstant.PS1_SCRIPTS_PATH}CreateMailboxBackupPermisssion.ps1 \
            {username} {self.m_password} \\\"{account_name}\\\""
        ret, std_out, std_err = execute_cmd(cmds)
        result = '\n'.join(std_out.splitlines()[-1:])
        if result == "True":
            return True
        log.error(f"mailbox create user permission failed, error: {std_out}!")
        return False

    def check_mailbox_backup_permissions(self):
        username = self.m_username.replace("\\", "\\\\")
        cmds = f"{ParamConstant.PS_LOC} {ParamConstant.PS1_SCRIPTS_PATH}CheckMailboxBackupPermisssion.ps1 \
            {username} {self.m_password}"
        ret, std_out, std_err = execute_cmd(cmds)
        result = '\n'.join(std_out.splitlines()[-1:])
        if result == "True":
            log.info(f"mailbox check user permission success!")
            return True
        log.info(f"mailbox check user permission failed!")
        return False

    def get_data_hub_and_meta_hub_path(self, job_id):
        self.meta_hub = os.path.join(self.get_unc_path(), job_id, "meta")
        self.data_hub = os.path.join(self.get_unc_path(), job_id, "data")
        log.info("get_data_hub_and_meta_hub_path finished!")

    def get_unc_path(self, index=1):
        return ExchangeWindowsPath.UNC + self._json_param.get('job').get('repositories')[index].get('path')[0]

    @exter_attack
    def backup_gen_sub_job(self):
        """
        生成子任务
        :return: True 运行成功, False 运行失败
        """
        log.info("mailbox backup_gen_sub_job start!")
        node_name = self._json_param.get("job").get("protectObject").get("extendInfo").get("PSComputerName")
        response = []
        node_type = self.check_node_type(node_name)
        if node_type == SINGLE_NODE or node_type == DAG_NODE:
            node_id = self.get_server_id(node_name)
            response.append(
                SubJobModel(jobId=self._job_id, subJobId=self._sub_job_id, jobType=2, jobName="ExchangeMailboxBackup",
                            execNodeId=node_id, ignoreFailed=self.backup_continue).dict(by_alias=True))
            # 拆分低优先级查询副本子任务
            response.append(SubJobModel(jobId=self._job_id, execNodeId=node_id, jobName='queryCopy', jobType=2,
                                        jobPriority=SubJobPriorityEnum.JOB_PRIORITY_4.value).dict(by_alias=True))
        output_result_file(self.pid, response)
        log.info("mailbox backup_gen_sub_job SUCCESS!")
        return True

    @exter_attack
    def query_backup_copy(self):
        """
        功能描述：查询备份副本, 备份成功, 执行后置任务之前执行, 备份失败不会调用
        参数：
        @pid： 请求ID
        @job_id： 主任务任务ID
        返回值：CommonBodyResponse
        """
        log.info(f'mailbox execute to query_backup_copy, pid: {self._job_id}, job_id: {self._sub_job_id}')
        copy_info = {}
        try:
            copy_id = self._json_param['job']['copy'][0]['id']
            repositories = self._json_param['job']['repositories']
            report_repositories = []
            for repository in repositories:
                repository_type = int(repository['repositoryType'])
                if repository_type == RepositoryDataTypeEnum.META_REPOSITORY.value or \
                        repository_type == RepositoryDataTypeEnum.DATA_REPOSITORY.value:
                    repository['remotePath'] = f"{repository['remotePath']}/{copy_id}"
                    report_repositories.append(repository)
            copy_info['repositories'] = report_repositories
            copy_info['extendInfo'] = {'copyId': copy_id}
        except Exception as e:
            log.error(e, exc_info=True)
        output_result_file(self.pid, copy_info)

    @exter_attack
    def abort_job(self):
        """
        功能描述：执行中止任务, 页面触发
        参数：
        @pid： 请求ID
        @job_id： 主任务任务ID
        返回值：CommonBodyResponse
        """
        log.info(f'execute to abort_job, job_id:{self._job_id}, sub_job_id:{self._sub_job_id}')
        if self._job_id is None or len(self._job_id) == 0:
            return True
        processes = psutil.process_iter()
        for process in processes:
            cmd_lines = process.cmdline()
            if len(cmd_lines) < 5:
                continue
            if str(self._job_id) == str(cmd_lines[4]) and (
                    str(cmd_lines[2]) in [TaskStage.BACKUP_PREREQUISITE, TaskStage.BACKUP_GEN_SUB_JOB,
                                          TaskStage.BACKUP]):
                stop_child_process(process)
                # windows下没有SIGKILL, 使用SIGTERM
                process.terminate()
                log.info(f"mailbox kill pid: {process.pid} for job id: {self._job_id} in stage: {cmd_lines[2]}")
        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        return True

    @exter_attack
    def backup(self):
        """
        备份
        :return: True 运行成功, False 运行失败
        """
        output = SubJobDetails(taskId=self._job_id, subTaskId=self._sub_job_id, progress=5,
                               logDetail=list(), taskStatus=SubJobStatusEnum.RUNNING.value).dict(by_alias=True)
        report_job_details_by_rpc(self._job_id, self.pid, self._sub_job_id, output)
        try:
            log.info("mailbox Backup Start!")
            # 获取要备份的邮箱 Guid
            self.guid = self._json_param.get("job").get("protectObject").get("id")
            # 获取要备份的邮箱
            self.mailbox_address = \
                self._json_param.get("job").get("protectObject").get("extendInfo").get("PrimarySmtpAddress")
            self.anonymization_mailbox = mailbox_anonymization(self.mailbox_address)
            self.m_progress = 50
            self.m_progress_status = SubJobStatusEnum.RUNNING.value
            self.get_data_hub_and_meta_hub_path(self._json_param.get("job").get("jobId"))
            final_data_path = self.data_hub
            final_data_path = final_data_path.replace("/", "\\")
            final_meta_path = self.meta_hub
            final_meta_path = final_meta_path.replace("/", "\\")
            repo_path = self.get_unc_path()
            self.windows_version = get_windows_server_version()
            log.info(f"guid: {self.guid}, mailbox: {self.anonymization_mailbox}, input_data_hub: {final_data_path}, "
                        f"input_meta_hub: {final_meta_path}, repo_path: {repo_path}, win_ver: {self.windows_version}")
            if self.set_job_type():
                self.backup_start_time = time.time()
                pub_meta = os.path.join(self._json_param.get("job").get("repositories")[0].get('path')[0], self._job_id)
                # 获取备份任务执行实例
                return_code_set = self.exec_backup(final_data_path, final_meta_path, repo_path, pub_meta)
                # 保存此次备份的任务相关信息
                self.write_backup_metadata(final_meta_path)
            else:
                log.error("mailbox set Backup Type Error!")
                output = SubJobDetails(taskId=self._job_id, subTaskId=self._sub_job_id, progress=100,
                                       logDetail=[], taskStatus=SubJobStatusEnum.FAILED.value, dataSize=0).dict(
                    by_alias=True)
                report_job_details_by_rpc(self._job_id, self.pid, self._sub_job_id, output)
                return False
            total_size = sum(self.process_shared_dict.get("total_size_list", [0])) // 1024  # 转成kb
            self.report_backup_result(return_code_set, total_size)
        except Exception as error:
            self.deal_with_backup_other_error(error)
            return False
        finally:
            clear(self.m_password)
        return True

    def report_backup_result(self, return_code_set, total_size):
        log.info(f"mailbox: Backup return_code_set {return_code_set} Backup!")
        if not return_code_set:
            task_status = SubJobStatusEnum.COMPLETED.value
            log_details = [
                LogDetail(logInfo=ExchangeReportDBLabel.SUB_JOB_SUCCESS,
                          logInfoParam=[self._sub_job_id], logLevel=LogLevel.INFO.value,
                          log_detail_param=[])
            ]
        else:
            log_details = [self.get_log_detail_from_error_code(error_code) for error_code in return_code_set]
            task_status = SubJobStatusEnum.FAILED.value
        output = SubJobDetails(taskId=self._job_id, subTaskId=self._sub_job_id, progress=100,
                               logDetail=log_details, taskStatus=task_status, dataSize=total_size).dict(
            by_alias=True)
        report_job_details_by_rpc(self._job_id, self.pid, self._sub_job_id, output)
        log.info(f"mailbox: {self.anonymization_mailbox} Backup SUCCESS!")

    def deal_with_backup_other_error(self, error):
        log_detail = self.get_log_detail_from_error_code(BodyErr.ERROR_INTERNAL.value)
        output = SubJobDetails(taskId=self._job_id, subTaskId=self._sub_job_id, progress=100,
                               logDetail=[log_detail], taskStatus=SubJobStatusEnum.FAILED.value, dataSize=0).dict(
            by_alias=True)
        log.error(error, exc_info=True)
        report_job_details_by_rpc(self._job_id, self.pid, self._sub_job_id, output)
        log.info(f"mailbox: {self.anonymization_mailbox} Backup Failed!")

    def get_log_detail_from_error_code(self, error_code):
        # 数据库状态异常或邮件超过大小限制，需要添加参数
        if error_code == BodyErr.BACKUP_FAIL_FOR_DATABASE_STATE_ABNORMAL.value:
            error_param = [self._json_param.get('job').get('protectObject').get('extendInfo').get('DatabaseName')]
        elif error_code == BodyErr.EMAIL_EXCEED_SIZE_LIMIT.value:
            error_param = [
                "1.4GB",
                self._json_param.get('job').get('protectObject').get('extendInfo').get('DatabaseName')
            ]
        else:
            error_param = []
        return LogDetail(logInfo=ExchangeReportDBLabel.SUB_JOB_FALIED,
                         logInfoParam=[self._sub_job_id], logLevel=LogLevel.ERROR.value,
                         logDetail=error_code, logDetailParam=error_param)

    def exec_backup(self, final_data_path, final_meta_path, repo_path, pub_meta_path) -> set[int]:
        mail_service = ExchangeMailBoxService(mailbox_name=self.mailbox_address,
                                              username=self.m_username,
                                              password=self.m_password,
                                              data_hub=final_data_path,
                                              meta_hub=final_meta_path,
                                              repo_path=repo_path,
                                              pub_meta_path=pub_meta_path,
                                              allow_half_success=self.backup_continue,
                                              job_id=self._job_id,
                                              pid=self.pid,
                                              process_num=self.process_num,
                                              windows_version=self.windows_version,
                                              sub_job_id=self._sub_job_id,
                                              compatibility_mode=self.compatibility_mode)
        # 初始化进程共享变量，统计备份邮件数
        self.process_shared_dict["backup_success_count_list"] = self.manager.list([0] * self.process_num)
        self.process_shared_dict["backup_failed_count_list"] = self.manager.list([0] * self.process_num)
        self.process_shared_dict["total_size_list"] = self.manager.list([0] * self.process_num)
        if self.job_type == ExchangeMailBosConstants.FULL_BACKUP:
            return mail_service.full_backup_entry(process_shared_dict=self.process_shared_dict)
        elif self.job_type == ExchangeMailBosConstants.INC_BACKUP:
            latest_copy_id = self._json_param.get('job').get('extendInfo').get('latest_copy_id')
            return mail_service.inc_backup_entry(latest_copy_id, self.process_shared_dict)
        else:
            log.error(f"unsupported job type {self.job_type}")
            raise ExchangeInternalException(f"unsupported job type {self.job_type}")

    def write_backup_metadata(self, metadata_path):
        meta_data = {
            "job_type": self.job_type,
            "backup_start_time": self.backup_start_time,
            "backup_end_time": time.time()
        }
        flags = os.O_WRONLY | os.O_CREAT
        modes = stat.S_IWUSR | stat.S_IRUSR | stat.S_IXUSR
        with os.fdopen(os.open(os.path.join(metadata_path, self.job_type), flags, modes), 'w') as f:
            json.dump(meta_data, f)

    @exter_attack
    def backup_post_job(self):
        """
        后置任务
        :return: True 运行成功, False 运行失败
        """
        log.info("backup_post_job Start!")
        job_result = self._json_param.get("backupJobResult")
        if job_result != BackupJobResult.SUCCESS:
            log.info(f"backup_post_job get job_result: {job_result}!")
            self.clean_data()

        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        self.write_progress_to_file(SubJobStatusEnum.COMPLETED.value, 100, "", "common")
        log.info("backup_post_job SUCCESS!")
        return True

    def clean_data(self):
        # 获取要备份的邮箱 Guid
        self.guid = self._json_param.get("job").get("protectObject").get("id")
        # data 仓
        final_path = os.path.join(self.get_unc_path(index=1), self._json_param.get("job").get("jobId"))
        final_path = final_path.replace("/", "\\")
        if os.path.exists(final_path):
            shutil.rmtree(final_path)
            log.info(f"mailbox clean data path: {final_path}")
        # Meta 仓
        final_path = os.path.join(self.get_unc_path(index=0), self._json_param.get("job").get("jobId"))
        final_path = final_path.replace("/", "\\")
        if os.path.exists(final_path):
            shutil.rmtree(final_path)
            log.info(f"mailbox clean meta path: {final_path}")
        log.info("mailbox clean data SUCCESS!")

    def set_job_type(self):
        ret = self._json_param.get("job").get("jobParam").get("backupType")
        log.info("Set Job Type:%d", ret)
        if ret == JobBackupType.EXCHANGE_BACKUP_FULL:
            self.job_type = ExchangeMailBosConstants.FULL_BACKUP
            return True
        elif ret == JobBackupType.EXCHANGE_BACKUP_INC:
            self.job_type = ExchangeMailBosConstants.INC_BACKUP
            return True
        else:
            log.error("Set job type Failed! JobBackupType Error!")
            return False

    def check_can_backup_inc(self):
        """
        检查是否需要增量转全量, 不存在全量备份, 增量需要转全量
        :return: True: 可以增量备份，False: 需要转成全量备份
        """
        log.info("check_can_backup_inc start!")
        try:
            # 获取要备份的邮箱 Guid
            self.guid = self._json_param.get("job").get("protectObject").get("id")
            root_meta_path = self.get_unc_path()
            if not os.path.exists(root_meta_path):
                log.error("No Full Backup Copy! Start Inc To Full!")
                return False
            files = os.listdir(root_meta_path)
            # 过滤掉文件和.snapshot目录
            dirs = list(filter(lambda x: os.path.isdir(os.path.join(root_meta_path, x)) and x != ".snapshot", files))
            # 按照文件夹最后修改时间反向排序
            dirs = sorted(dirs, key=lambda x: -1 * os.path.getmtime(os.path.join(root_meta_path, x)))
            for dir_name in dirs:
                # 存在全量备份元数据文件，可以进行增量备份
                full_backup_file = os.path.join(root_meta_path, dir_name, ExchangeMailBosConstants.META_DIR,
                                                ExchangeMailBosConstants.FULL_BACKUP)
                if os.path.exists(full_backup_file):
                    log.info(f"exist: check_can_backup_inc SUCCESS!")
                    return True
            log.error("No Full Backup Copy! Start Inc To Full!")
            return False
        except Exception as error:
            log.error(error, exc_info=True)
            log.error("check_can_backup_inc FAILED!")
            return False

    def init_cache_and_data_directory(self, data_hub_path, meta_hub_path):
        log.info("init_cache_and_data_directory start!")
        ori_meta_hub_path = os.path.join(self._json_param.get("job").get("repositories")[0].get('path')[0],
                                         self._job_id)
        path_list = [data_hub_path, meta_hub_path, ori_meta_hub_path]
        for path in path_list:
            try:
                if not os.path.exists(path):
                    os.makedirs(path)
            except Exception as error:
                log.error(error, exc_info=True)
                log.info("mailbox init_cache_and_data_directory FAILED!")
                return False
            else:
                continue
        log.info("init cache SUCCESS!")
        return True

    @exter_attack
    def query_job_permission(self):
        output_action_result(self.pid, ExchangeCode.SUCCESS.value, 0, "")
        return True

    def check_node_type(self, node_name):
        log.info("check_node_type start!")
        username = self.m_username.replace("\\", "\\\\")
        cmds = f"{ParamConstant.PS_LOC} {ParamConstant.PS1_SCRIPTS_PATH}CheckNodeType.ps1 \
            {username} {self.m_password} {node_name}"
        ret, std_out, std_err = execute_cmd(cmds)
        result = '\n'.join(std_out.splitlines()[-1:])

        return result

    def get_server_id(self, server_name):
        """
        获取节点id
        :return: 节点id
        """
        log.info("get_server_id start!")
        username = self.m_username.replace("\\", "\\\\")
        cmds = f"{ParamConstant.PS_LOC} {ParamConstant.PS1_SCRIPTS_PATH}GetServerGuid.ps1 \
            {username} {self.m_password} {server_name}"
        ret, std_out, std_err = execute_cmd(cmds)
        result = '\n'.join(std_out.splitlines()[-1:])
        return result

    @exter_attack
    def progress_comm(self):
        """
        进度上报
        :return: True 运行成功, False 运行失败
        """
        log.info("mailbox backup progress_com Start!!!")
        self.report_progress_comm()
        log.info("mailbox backup progress_com Finished!!!")
        return True


def do_work(args_list):
    log.info("exchange mailbox do_work start!")
    cmd = args_list[0]
    pid = args_list[1]
    job_id = ""
    sub_job_id = ""
    if len(args_list) >= 3:
        job_id = args_list[2]
    if len(args_list) == 4:
        sub_job_id = args_list[3]
    backup_comm_inst = ExchangeMailboxBackupComm(pid, job_id, sub_job_id)

    flags, backup_comm_inst.m_username = get_key_value(f'job_protectEnv_auth_authKey_{pid}')
    if not flags:
        log.error("get username FAILED")
        return False
    flags, backup_comm_inst.m_password = get_key_value(f'job_protectEnv_auth_authPwd_{pid}')
    if not flags:
        log.error("get user password FAILED")
        return False

    cmd_dict = {
        "AllowBackupInLocalNode": [backup_comm_inst.allow_backup_in_local_node],
        "BackupPrerequisite": [backup_comm_inst.backup_prerequisite],
        "Backup": [backup_comm_inst.backup],
        "BackupPostJob": [backup_comm_inst.backup_post_job],
        "QueryJobPermission": [backup_comm_inst.query_job_permission],
        "progress_comm": [backup_comm_inst.progress_comm],
        "BackupGenSubJob": [backup_comm_inst.backup_gen_sub_job],
        "CheckBackupJobType": [backup_comm_inst.check_backup_job_type],
        'AbortJob': [backup_comm_inst.abort_job],
        'QueryBackupCopy': [backup_comm_inst.query_backup_copy],
    }
    func_array = cmd_dict.get(cmd)
    if not func_array:
        output_action_result(pid, ExchangeCode.FAILED.value, BodyErr.ERROR_INTERNAL.value, f"Cmd Param error.")
        return False
    try:
        ret = func_array[0]()
    except Exception as err:
        log.error(f"Exec cmd failed as err: {str(err)} pid: {pid} jobId: {job_id}")
        return False
    finally:
        clear(SysData.SYS_STDIN)
    return ret


if __name__ == "__main__":
    log.info("Running exchange mailbox backup main....")
    for line in sys.stdin:
        SysData.SYS_STDIN = line
        break

    args = sys.argv[1:]
    if len(args) < 2:
        log.error("Not enough parameters, param cnt: %s.", len(args))
        sys.exit(1)
    if not do_work(args):
        sys.exit(0)
